package com.sxd.bill.rela.util;

import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collections;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
import java.util.stream.Collectors;

public class Normalizer {
    private static ArrayList<DueGetter> dueGetters = new ArrayList<>();

    static {
        dueGetters.add(new DigitDueGetter());
        dueGetters.add(new ZHNumDueGetter());
        dueGetters.add(new QuarterDueGetter());
        dueGetters.add(new DueDueGetter());
        dueGetters.add(new DateDueGetter());
        dueGetters.add(new CurrentDueGetter());
        dueGetters.add(new JanuaryDueGetter());
    }

    private static DueItem extractDueItem(String dueText) {
        if (dueText != null) {
            for (DueGetter getter : dueGetters) {
                DueItem item = getter.getDue(dueText);
                if (!item.isNull()) {
                    return item;
                }
            }
        }
        return new DueItem();
    }

    /**
     * 标准化 票据期限
     */
    public static List<String> normalizeDue(List<String> dueTexts, Integer curMon) {
        List<DueItem> items = dueTexts.stream().map(txt -> extractDueItem(txt)).collect(Collectors.toList());
        List<Integer> months = new ArrayList<>();
        List<Integer> dues = new ArrayList<>();
        for (DueItem item : items) {
            Integer due = item.getDue();
            if (due != null) {
                dues.add(due);
            }
            Integer mon = item.getMonth();
            if (mon != null) {
                months.add(mon);
            }
        }
        if (dues.size() > 0) {
            Integer maxDue = Collections.max(dues);
            String normalizedDue = maxDue == 0 ? "托收" : String.format("%dM", maxDue);
            return Arrays.asList(normalizedDue);
        } else if (months.size() > 0) {
            Integer maxMon = Collections.max(months);
            if (curMon != null) {
                Integer due = maxMon > curMon ? maxMon - curMon : maxMon - curMon + 12; // +12是因为月份跨年
                String normalizedDue = due == 0 ? "托收" : String.format("%dM", due);
                return Arrays.asList(normalizedDue);
            } else {
                return dueTexts;
            }
        } else {
            return dueTexts;
        }
    }

    /**
     * 标准化 交易方向
     */
    public static String normalizeTradingDirection(String tradingDirection) {
        if (tradingDirection == null) {
            return tradingDirection;
        } else if (Pattern.matches(".*[买收入].*", tradingDirection)) {
            return "收票";
        } else if (Pattern.matches(".*[出卖].*", tradingDirection)) {
            return "出票";
        } else {
            return tradingDirection;
        }
    }
}

class DueItem {
    private Integer month;
    private Integer due;

    public void setMonth(String month) {
        this.month = Integer.parseInt(month);
    }

    public void setMonth(Integer month) {
        this.month = month;
    }

    public void setDue(String due) {
        this.due = Integer.parseInt(due);
    }

    public void setDue(Integer due) {
        this.due = due;
    }

    public Integer getMonth() {
        return month;
    }

    public Integer getDue() {
        return due;
    }

    public boolean isNull() {
        return month == null && due == null;
    }
}

interface DueGetter {
    public DueItem getDue(String dueText);
}

/**
 * 票据期限文本形式为"阿拉伯数字+月份"的情况
 */
class DigitDueGetter implements DueGetter {
    public DueItem getDue(String DueText) {
        DueItem dueItem = new DueItem();
        Matcher m = Pattern.compile("(1[012]|\\d)\\s*月").matcher(DueText);
        if (m.find()) {
            dueItem.setMonth(m.group(1));
        }
        return dueItem;
    }
}

/**
 * 票据期限文本形式为"中文数字+月份"的情况
 */
class ZHNumDueGetter implements DueGetter {
    private static Pattern zhPattern = Pattern.compile("(十[一二]|[一二三四五六七八九十])\\s*月");
    private static Map<String, Integer> ZHNum2month = new HashMap<>();
    static {
        ZHNum2month.put("一", 1);
        ZHNum2month.put("二", 2);
        ZHNum2month.put("三", 3);
        ZHNum2month.put("四", 4);
        ZHNum2month.put("五", 5);
        ZHNum2month.put("六", 6);
        ZHNum2month.put("七", 7);
        ZHNum2month.put("八", 8);
        ZHNum2month.put("九", 9);
        ZHNum2month.put("十", 10);
        ZHNum2month.put("十一", 11);
        ZHNum2month.put("十二", 12);
    }

    public DueItem getDue(String DueText) {
        DueItem dueItem = new DueItem();
        Matcher m = zhPattern.matcher(DueText);
        if (m.find()) {
            String CNN = m.group(1);
            dueItem.setMonth(ZHNum2month.get(CNN));
        }
        return dueItem;
    }
}

/**
 * 票据期限文本形式为"数字+季度"的情况
 */
class QuarterDueGetter implements DueGetter {
    private static Pattern quarterPattern = Pattern.compile("([一二三四1234])\\s*季度");
    private static Map<String, Integer> quarter2month = new HashMap<>(); // 季度 -> 月份
    static {
        quarter2month.put("一", 3);
        quarter2month.put("二", 6);
        quarter2month.put("三", 9);
        quarter2month.put("四", 12);
        quarter2month.put("1", 3);
        quarter2month.put("2", 6);
        quarter2month.put("3", 9);
        quarter2month.put("4", 12);
    }

    public DueItem getDue(String DueText) {
        DueItem dueItem = new DueItem();
        Matcher m = quarterPattern.matcher(DueText);
        if (m.find()) {
            String q = m.group(1);
            dueItem.setMonth(quarter2month.get(q));
        }
        return dueItem;
    }
}

/**
 * 本月到期
 */
class CurrentDueGetter implements DueGetter {
    private static Pattern currPattern = Pattern.compile("(当月|月[初中末底内]|本月|\\d+[日号]|上旬|下旬|中旬|托收)");

    public DueItem getDue(String DueText) {
        DueItem dueItem = new DueItem();
        Matcher m = currPattern.matcher(DueText);
        if (m.find()) {
            dueItem.setDue(0);
        }
        return dueItem;
    }
}

/**
 * MM.DD
 */
class DateDueGetter implements DueGetter {
    private static Pattern datePattern = Pattern.compile("(1[012]|\\d)\\.[0123]?\\d");

    public DueItem getDue(String DueText) {
        DueItem dueItem = new DueItem();
        Matcher m = datePattern.matcher(DueText);
        ArrayList<Integer> months = new ArrayList<>();
        while (m.find()) {
            String mon = m.group(1);
            months.add(Integer.parseInt(mon));
        }
        if (months.size() > 0) {
            Integer maxMonth = Collections.max(months);
            dueItem.setMonth(maxMonth);
        }
        return dueItem;
    }
}

/**
 * `数字 + M`
 */
class DueDueGetter implements DueGetter {
    private static Pattern duePattern = Pattern.compile("(\\d+)M");

    public DueItem getDue(String DueText) {
        DueItem dueItem = new DueItem();
        Matcher m = duePattern.matcher(DueText);
        if (m.find()) {
            String due = m.group(1);
            dueItem.setDue(due);
        }
        return dueItem;
    }
}

class JanuaryDueGetter implements DueGetter {
    private static Pattern janPattern = Pattern.compile("跨年\\s*$");

    public DueItem getDue(String DueText) {
        DueItem dueItem = new DueItem();
        Matcher m = janPattern.matcher(DueText);
        if (m.find()) {
            dueItem.setMonth(1);
        }
        return dueItem;
    }
}